﻿using System.Text.Json.Serialization;

namespace Devonline.AspNetCore;

/// <summary>
/// 嵌套的查询过滤选项, 代表字段内的字段和值的关系
/// 典型样式为: 
/// Name eq '张三'
/// Age gt 20
/// contains(Name, '张三')
/// not support: contains(tolower(Name), 'lucy')
/// not support: Name not eq '张三'
/// not support: Name eq '张三' and Age ge 20
/// not support: Age ge 20 and (startswith(Name, '张') or endswith(Name, '李'))
/// not support: Age ge 20 and (contains(Name, '张') or contains(Name, '李') or Gender eq 'Male')
/// not support: Age ge 20 and (contains(Name, '张') or contains(Name, '李')) and Gender eq 'Male'
/// not support: Age ge 20 and (contains(Name, '张') or contains(Name, '李')) and (Gender eq 'Male' or UserType eq 'Administrator')
/// </summary>
public class NestedFilterOption : FilterOption
{
    /// <summary>
    /// logic expression list
    /// </summary>
    internal static readonly string[] LogicExpression = new string[] { " and ", " or " };

    /// <summary>
    /// 默认构造函数
    /// </summary>
    public NestedFilterOption(Type type) : base(type) { }
    /// <summary>
    /// 字符串 filter 表示形式参数的构造函数
    /// </summary>
    /// <param name="filter"></param>
    public NestedFilterOption(Type type, string filter) : base(type, filter)
    {
        //目前仅支持一级嵌套, 且不支持小括号表达式
        var values = filter.Split(LogicExpression, StringSplitOptions.RemoveEmptyEntries);
        if (values.IsNullOrEmpty())
        {
            throw new ArgumentException($"filter {filter} expression error!");
        }

        var filters = new List<FilterOption>();
        foreach (var value in values)
        {
            filters.Add(new FilterOption(type, value));
        }

        Filters = filters;
    }

    /// <summary>
    /// 内部字段之间的逻辑, and, or等
    /// </summary>
    [JsonPropertyName("logic")]
    public LogicType? Logic { get; set; }
    /// <summary>
    /// 内部字段选项
    /// </summary>
    [JsonPropertyName("filters")]
    public IEnumerable<FilterOption>? Filters { get; set; }

    /// <summary>
    /// 重载的方法返回字符串形式表达式
    /// </summary>
    /// <returns></returns>
    public override string ToString() => base.ToString();

    /// <summary>
    /// get filter expressions logic
    /// </summary>
    /// <param name="logicType"></param>
    /// <returns></returns>
    public string GetFilterLogic() => Logic switch
    {
        LogicType.And => " && ",
        LogicType.Or => " || ",
        _ => throw new ArgumentException($"{Logic} is not support"),
    };
}

/// <summary>
/// 嵌套的查询过滤选项, 代表字段内的字段和值的关系
/// 典型样式为: 
/// Name eq '张三'
/// Age gt 20
/// contains(Name, '张三')
/// not support: contains(tolower(Name), 'lucy')
/// not support: Name not eq '张三'
/// not support: Name eq '张三' and Age ge 20
/// not support: Age ge 20 and (startswith(Name, '张') or endswith(Name, '李'))
/// not support: Age ge 20 and (contains(Name, '张') or contains(Name, '李') or Gender eq 'Male')
/// not support: Age ge 20 and (contains(Name, '张') or contains(Name, '李')) and Gender eq 'Male'
/// not support: Age ge 20 and (contains(Name, '张') or contains(Name, '李')) and (Gender eq 'Male' or UserType eq 'Administrator')
/// </summary>
public class NestedFilterOption<T> : FilterOption<T>
{
    /// <summary>
    /// logic expression list
    /// </summary>
    internal static readonly string[] LogicExpression = new string[] { " and ", " or " };

    /// <summary>
    /// 默认构造函数
    /// </summary>
    public NestedFilterOption() { }
    /// <summary>
    /// 字符串 filter 表示形式参数的构造函数
    /// </summary>
    /// <param name="filter"></param>
    public NestedFilterOption(string filter)
    {
        //目前仅支持一级嵌套, 且不支持小括号表达式
        var values = filter.Split(LogicExpression, StringSplitOptions.RemoveEmptyEntries);
        if (values.IsNullOrEmpty())
        {
            throw new ArgumentException($"filter {filter} expression error!");
        }

        var filters = new List<FilterOption<T>>();
        foreach (var value in values)
        {
            filters.Add(new FilterOption<T>(value));
        }

        Filters = filters;
    }

    /// <summary>
    /// 内部字段之间的逻辑, and, or等
    /// </summary>
    [JsonPropertyName("logic")]
    public LogicType? Logic { get; set; }
    /// <summary>
    /// 内部字段选项
    /// </summary>
    [JsonPropertyName("filters")]
    public IEnumerable<FilterOption<T>>? Filters { get; set; }

    public override string ToString()
    {
        return base.ToString();
    }

    /// <summary>
    /// get filter expressions logic
    /// </summary>
    /// <param name="logicType"></param>
    /// <returns></returns>
    public string GetFilterLogic() => Logic switch
    {
        LogicType.And => " && ",
        LogicType.Or => " || ",
        _ => throw new ArgumentException($"{Logic} is not support"),
    };
}